package insertionSort;

import shared.Buffer;
import shared.MyComparable;
import shared.MyStop;
import shared.SortInput;
import shared.SortInputVisitor;

public class InsertionSorter<T extends Comparable<? super T>> {
	
	private final Buffer<SortInput<T>> inputBuffer;
	private final Buffer<InputProcessor<T>> processors;
	private InputProcessor<T> topProcessor;
	private boolean topProcessorSet;

	public Buffer<SortInput<T>> getInputBuffer() {
		return inputBuffer;
	}
	public Buffer<InputProcessor<T>> getProcessorBuffer() {
		return processors;
	}
	private InputProcessor<T> getTopProcessor() {
		return this.topProcessor;
	}
	private void setTopProcessor(final InputProcessor<T> newTopProcessor){
		this.topProcessor = newTopProcessor;
		this.setTopProcessorSet(true);
	}
	public boolean isTopProcessorSet() {
		return topProcessorSet;
	}
	public void setTopProcessorSet(final boolean topProcessorSet) {
		this.topProcessorSet = topProcessorSet;
	}
	/**
	 * Constructor of {@link InsertionSorter}.
	 * @param inputBuffer is a buffer with {@link MyComparable}s that are to be sorterd and a {@link MyStop} at the end.
	 */
	public InsertionSorter(final Buffer<SortInput<T>> inputBuffer) {
		this.inputBuffer = new Buffer<SortInput<T>>();
		this.processors = new Buffer<InputProcessor<T>>();
		while(!inputBuffer.isEmpty()){
			final SortInput<T> input = inputBuffer.get();
			this.getInputBuffer().put(input);
			input.accept(new SortInputVisitor<T>() {

				@Override
				public void visit(final MyComparable<T> myComparable) {
					
					final InputProcessor<T> processor;
					if(InsertionSorter.this.isTopProcessorSet()){
						processor = new InputOutputProcessor<>(InsertionSorter.this.getTopProcessor());
					} else {
						processor = new ConcreteInputProcessor<T>();
					}
					InsertionSorter.this.getProcessorBuffer().put(processor);
					InsertionSorter.this.setTopProcessor(processor);
				}

				@Override
				public void visit(final MyStop<T> myStop) {
					
				}
			});
		}	

	}
	

	public Buffer<T> getResult(){
		final Buffer<T> result = new Buffer<T>();
		if(this.isTopProcessorSet()){
			while(!this.getInputBuffer().isEmpty()){
				final SortInput<T> input = this.getInputBuffer().get();
				this.getTopProcessor().getInputBuffer().put(input);
			}

			while(!this.getProcessorBuffer().isEmpty()){
				result.put(this.getProcessorBuffer().get().getResult());
			}
		}		
		return result;
	}


	
}
